package awareness;

import awareness.communication.ServiceListener;
import awareness.communication.StatisticsServer;
import javax.bluetooth.L2CAPConnection;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.UUID;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

import awareness.gui.AwarenessCanvas;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.microedition.io.Connector;
import javax.microedition.io.InputConnection;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.file.FileConnection;

public class AwarenessMidlet extends MIDlet implements CommandListener {

    private Display display;
    private List languageList;
    private AwarenessCanvas canvas;
    private List visitorList;
    private List contactList;
    public static int[] quizValues;
    public static String quizString;
    public static int agreeIndex = -1;
    public static int language = 0; // 0 - Eesti, 1 - English
    private LocalDevice local_device;
    private String my_name;
    private DiscoveryAgent disc_agent;
    public InquiryListener inquiry_listener;
    private ServiceListener service_listener;
    private StatisticsServer server;
    private boolean isInquiryStarted;
    private AwarenessMidlet me;
    private final UUID[] uuids = new UUID[]{new UUID("00000000000010008000006057028A06", false)};
    private final int attrbs[] = {0x0100};
    private boolean searching = false;
    private String[] buttonText = null;
    public static  int index = 0;
    private Timer timer;
    private TimerTask timerTask;
    public boolean isNextToYou = false;

    public final int REFRESH_TIME = 7 * 1000 * 60;


    public AwarenessMidlet() {

        display = Display.getDisplay(this);

        languageList = new List("Language/Keel", List.IMPLICIT);

        Image imgEnglish = null;
        Image imgEesti = null;
        try {
            imgEnglish = Image.createImage("/uk.gif");
            imgEesti = Image.createImage("/estonia.gif");
        } catch (IOException e) {
        }

        languageList.append("Eesti", imgEesti);
        languageList.append("English", imgEnglish);

        Command cmd_ok = new Command("OK", Command.OK, 10);
        languageList.addCommand(cmd_ok);
        languageList.setCommandListener(this);

        quizValues = new int[5];
        quizString = new String();
        reset();
        quizValues = getIntArrayFromString(quizString);

        initBtooth();

        server = new StatisticsServer(this, this.quizString);

        timer = new Timer();
        timerTask = new Refresh();

    }

    public void startApp() {
        display.setCurrent(languageList);
        //setAlert("Width: " + canvas.getWidth()+ "\nHeight: " + canvas.getHeight());
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }

    public void commandAction(Command command, Displayable d) {

        if (command.getCommandType() == Command.OK) { // LANGUAGE
            canvas = new AwarenessCanvas(this);
            switch (languageList.getSelectedIndex()) {
                case 0: {
                    AwarenessMidlet.language = 0;
                    canvas.setTextLanguage(eesti);
                    buttonText = buttonsEesti;
                    break;
                }
                case 1: {
                    AwarenessMidlet.language = 1;
                    canvas.setTextLanguage(english);
                    buttonText = buttonsEnglish;
                    break;
                }
                default: {
                    break;
                }
            }

            //Command cmd_refresh = new Command(buttonText[0], Command.SCREEN, 20);
            //canvas.addCommand(cmd_refresh);
            Command cmd_all = new Command(buttonText[1], Command.SCREEN, 10);
            canvas.addCommand(cmd_all);
            canvas.setCommandListener(this);

            visitorList = new List(buttonText[6], List.IMPLICIT);
            /*visitorList.append(buttonText[7] + " 01", null);
            visitorList.append(buttonText[7] + " 02", null);
            visitorList.append(buttonText[7] + " 04", null);
            visitorList.append(buttonText[7] + " 10", null);
             */
            Command cmd_choose = new Command(buttonText[2], Command.ITEM, 10);
            visitorList.addCommand(cmd_choose);
            Command cmd_back = new Command(buttonText[3], Command.EXIT, 30);
            visitorList.addCommand(cmd_back);
            visitorList.setCommandListener(this);

            /*
            contactList = new List(buttonText[5], List.IMPLICIT);
            contactList.append("Send :)", null);
            contactList.append("Send :(", null);
            contactList.append("Send :D", null);
            contactList.append("Send :S", null);

            Command cmd_send = new Command(buttonText[4], Command.ITEM, 20);
            contactList.addCommand(cmd_send);
            contactList.addCommand(cmd_back);
            contactList.setCommandListener(this);
             */

            AwarenessCanvas.showLoadingBar = true;
            display.setCurrent(canvas);

            discoverDevices();

            timer.scheduleAtFixedRate(timerTask, REFRESH_TIME, REFRESH_TIME);

        } else if (command.getCommandType() == Command.ITEM && command.getPriority() == 10) { // SELECT VISITOR
            // prikazati podatke za odabranog visitora
            index = visitorList.getSelectedIndex();
            agreeIndex = -1;
            AwarenessCanvas.showLoadingBar = true;
            if (AwarenessMidlet.language == 0) {
                canvas.setTextLanguage(eesti2);
            } else {
                canvas.setTextLanguage(english2);
            }

            display.setCurrent(canvas);
            RemoteDevice chosen_device = inquiry_listener.getRemoteDevice(index);
            Thread t = new Thread(new Client(me, chosen_device));
            t.start();
            //setAlert("Odabaran taj i taj visitor...");
        } else if (command.getCommandType() == Command.ITEM && command.getPriority() == 20) { // SEND MESSAGE
            // poslati poruku
            display.setCurrent(canvas);
            //setAlert("Poslana poruka tom i tom visitoru...");
        } else if (command.getCommandType() == Command.EXIT) { // BACK
            display.setCurrent(canvas);
        } else if (command.getCommandType() == Command.SCREEN) {
            if (command.getPriority() == 10) { // SEE ALL
                if (!AwarenessCanvas.showLoadingBar) {
                    display.setCurrent(visitorList);
                }
            } /*else if (command.getPriority() == 20) { // REFRESH
                if (!LoadingBarCanvas.showLoadingBar) {
                    index = 0;
                    LoadingBarCanvas.showLoadingBar = true;
                    display.setCurrent(canvas);
                    discoverDevices();
                }
            }*/
            /*
            try {
            InputStream in = getClass().getResourceAsStream("/sound.wav");
            Player player = Manager.createPlayer(in, "audio/x-wav");
            player.prefetch();
            player.start();
            in.close();
            } catch (Exception e) {
            e.printStackTrace();
            }
             */
        }
    }

    public void setAlert(String info) {
        Alert a = new Alert("INFO");
        a.setString(info);
        a.setTimeout(Alert.FOREVER);
        display.setCurrent(a);
    }

    private void reset() {
        try {
            InputConnection fc = (FileConnection) Connector.open("file:///Others/ans.txt");

            InputStream fis = fc.openInputStream();
            DataInputStream fdi = new DataInputStream(fis);

            int ch;
            while ((ch = fdi.read()) != -1) {
                quizString += ((char) ch);
            }

            fdi.close();
            fis.close();
            fc.close();
        } catch (Exception e) {
            for (int i = 0; i < 5; i++) {
                quizValues[i] = 0;
            }
            quizString = "0-0-0-0-0";
        }
    }

    public static int[] getIntArrayFromString(String s) {
        int[] values = new int[5];

        char c;
        int j = 0;
        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            if (c >= 49 && c <= 53) {
                values[j++] = c - 48;
            }
        }

        if (j != 5) {
            for (int i = 0; i < 5; i++) {
                values[i] = 0;

            }
        }

        return values;
    }

    public static int getAgreeIndex(int[] a, int[] b) {

        if (a[0] == 0 || b[0] == 0) {
            return -1;
        }

        int index;
        int sum = 0;

        for (int i = 0; i < 5; i++) {
            sum += Math.abs(a[i] - b[i]);
        }

        index = 100 - 5 * sum;

        return index;
    }

    public static String[] getTextFromFile(String filename) {
        String[] text = new String[3];
        try {
            InputConnection fc = (FileConnection) Connector.open("file:///Others/" + filename);

            InputStream fis = fc.openInputStream();
            DataInputStream fdi = new DataInputStream(fis);

            int ch;
            int i = 0;
            String s = "";
            while ((ch = fdi.read()) != -1) {
                if (ch != '\n' && ch != '\r') {
                    s += ((char) ch);
                } else if (ch == '\n') {
                    text[i] = s;
                    s = "";
                    i++;
                }
            }
            text[i] = s;

            fdi.close();
            fis.close();
            fc.close();
        } catch (Exception e) {
        }
        return text;
    }
    //public String[] english = getTextFromFile("english.txt");
    public static String[] english = {"YOU AGREE ", // 0
        "WITH THE PERSON", // 1
        "NEXT TO YOU", // 2
    };
    //public String[] eesti = getTextFromFile("eesti.txt");
    public static String[] eesti = {"SINU ARVAMUS", // 0
        "ÜHTIB ", // 1
        " INIMESEGA", // 2
        "SINU LÄHEDAL", // 3
    };
    
    public static String[] english2 = {"YOU AGREE", // 0
        " WITH", // 1
        "VISITOR "
    };
    public static String[] eesti2 = {"NÕUSTUD", // 0
        "KÜLASTAJAGA ", // 1
    };

    public static String[] english3 = {"SORRY, VISITOR ", // 0
        "IS NOT AVAILABLE.", // 1
        "TRY LATER."
    };
    public static String[] eesti3 = {"KAHJUKS EI OLE", // 0
        "KÜLASTAJA ", // 1
        "SAADAVAL.", // 2
        "PROOVI HILJEM"
    };

    public String[] buttonsEnglish = {"REFRESH", // 0
        "SEE ALL", // 1
        "SELECT", // 2
        "BACK", // 3
        "SEND", // 4
        "Send message", // 5
        "Visitors in range", // 6
        "VISITOR", // 7
    };
    public String[] buttonsEesti = {"VÄRSKENDA", // 0
        "VAATA KÕIKI", // 1
        "VALI", // 2
        "TAGASI", // 3
        "SAADA", // 4
        "SAADA SÕNUM", // 5
        "Külastajad lähiulatuses", // 6
        "KÜLASTAJA", // 7
    };

    /* BLUETOOTH CLIENT */
    public synchronized void setCanvas() {
        display.setCurrent(canvas);
    }

    private void initBtooth() {
        try {
            local_device = LocalDevice.getLocalDevice();
            local_device.setDiscoverable(DiscoveryAgent.GIAC);
            my_name = local_device.getFriendlyName();
            disc_agent = local_device.getDiscoveryAgent();

            inquiry_listener = new InquiryListener();
            inquiry_listener.addActionListener(new ActionListener() {

                public void actionPerformed() {
                    makeDeviceList();
                }
            });
            inquiry_listener.addActionListener(new ActionListener() {

                public void actionPerformed() {
                    //while (isInquiryStarted);
                    if (visitorList.size() != 0) {
                        RemoteDevice chosen_device = inquiry_listener.getRemoteDevice(0);
                        Thread t = new Thread(new Client(me, chosen_device));
                        t.start();
                    }
                }
            });

            service_listener = new ServiceListener();
        } catch (Exception e) {
        }
    }

    private void discoverDevices() {
        if (isInquiryStarted) {
            return;
        }
        isInquiryStarted = true;
        isNextToYou = true;
        synchronized (inquiry_listener) {
            try {
                disc_agent.startInquiry(DiscoveryAgent.GIAC, inquiry_listener);
            } catch (BluetoothStateException e) {
            }
        }
    }

    private void makeDeviceList() {
        visitorList.deleteAll();
        for (int i = 0; i < inquiry_listener.devicesNum(); i++) {
            RemoteDevice d = (RemoteDevice) inquiry_listener.getRemoteDevice(i);
            try {
                visitorList.append(buttonText[7] + " " + d.getFriendlyName(false).substring(3), null);
            } catch (Exception e) {
            }
        }
        isInquiryStarted = false;
    }

    public class InquiryListener implements DiscoveryListener {

        private boolean isNewInquiry;
        private Vector cached_devices;
        public Vector action_listeners;

        public InquiryListener() {
            isNewInquiry = true;
            cached_devices = new Vector();
            action_listeners = new Vector();
        }

        public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {

            if (isNewInquiry) {
                cached_devices.removeAllElements();
                isNewInquiry = false;
            }

            boolean isFriend = false;
            try {
                if (btDevice.getFriendlyName(false).startsWith("TAL")) {
                    isFriend = true;
                } else {
                    isFriend = false;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (!cached_devices.contains(btDevice) && isFriend) {
                cached_devices.addElement(btDevice);

            }
        }

        public void inquiryCompleted(int discType) {
            isNewInquiry = true;
//        synchronized (this) {
//            this.notify();
//        }
            notifyListeners();
        }

        public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
        }

        public void serviceSearchCompleted(int transID, int respCode) {
        }

        public void addActionListener(ActionListener a) {
            action_listeners.addElement(a);
        }

        private void notifyListeners() {
            for (int i = 0; i < action_listeners.size(); i++) {
                ActionListener al = (ActionListener) action_listeners.elementAt(i);
                al.actionPerformed();

            }
        }

        public synchronized RemoteDevice getRemoteDevice(int index) {
            return (RemoteDevice) cached_devices.elementAt(index);
        }

        public synchronized int devicesNum() {
            return cached_devices.size();
        }
    }

    interface ActionListener {

        void actionPerformed();
    }

    class Client implements Runnable {

        private RemoteDevice remote_device;
        private AwarenessMidlet midlet;

        public Client(AwarenessMidlet _midlet, RemoteDevice remoteDevice) {
            remote_device = remoteDevice;
            midlet = _midlet;
        }

        public void run() {
            final UUID[] uuids = new UUID[]{new UUID("00000000000010008000006057028A06", false)};
            final int attrbs[] = {0x0100};
            DiscoveryAgent disc_agent = null;
            try {
                LocalDevice local_device = LocalDevice.getLocalDevice();
                local_device.setDiscoverable(DiscoveryAgent.GIAC);
                String my_name = local_device.getFriendlyName();
                disc_agent = local_device.getDiscoveryAgent();
            } catch (Exception e) {
            }
            String message = "nije ništa doslo";
            ServiceListener service_listener = new ServiceListener();

            synchronized (service_listener) {
                int transID = -1;
                try {
                    transID = disc_agent.searchServices(attrbs, uuids, remote_device, service_listener);
                } catch (BluetoothStateException e) {
                }
                try {
                    Thread.sleep(2000);
                    disc_agent.cancelServiceSearch(transID);
                } catch (InterruptedException e) {
                }

                if (service_listener.getService() != null) {
                    String url = service_listener.getService().getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                    L2CAPConnection connection = null;
                    try {
                        connection = (L2CAPConnection) Connector.open(url);
                    } catch (IOException e) {
                        message = "Connector threw an exception :(";
                    }
                    try {
                        while (true) {
                            if (connection.ready()) {
                                byte[] b = new byte[20];
                                connection.receive(b);
                                message = new String(b, 0, b.length);
                                break;
                            }
                        }
                    } catch (IOException e) {
                        message = "connection read threw an exception: " + e.getMessage();
                    }
                } else {
                    message = "no services found";
                }
            }
            agreeIndex = getAgreeIndex(quizValues, getIntArrayFromString(message));
            if (agreeIndex == -1){
                if (isNextToYou) {
                    display.setCurrent(visitorList);
                    isNextToYou = false;
                } else {

                }
            }
            AwarenessCanvas.showLoadingBar = false;
            canvas.playSound();
        }
    }

    public final class Refresh extends TimerTask {

        public void run() {
            if (!AwarenessCanvas.showLoadingBar) {
                index = 0;
                AwarenessCanvas.showLoadingBar = true;
                display.setCurrent(canvas);
                discoverDevices();
            }
        }
    }
}
